﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Skybot.Net.WebSockets.Sockets
{

    using System.Net;
    using System.Net.Sockets;
    /// <summary>
    /// 
    /// </summary>
    public class AsyncSocketServer:System.IDisposable
    {

        #region 变量定义

        /// <summary>
        /// Socket 服务器对像
        /// </summary>
        protected Socket ServerListen = null;
        /// <summary>
        /// Socket 邦定监听端口的设置
        /// </summary>
        private IPEndPoint _ServerEndPoint = null;

        /// <summary>
        /// 获取当前邦定监听的终结点
        /// </summary>
        protected EndPoint ServerIPEndPoint
        {
            get { return _ServerEndPoint; }
        }


        /// <summary>
        /// 最大接收客户端联接数 默认值10000
        /// </summary>
        private int _MaxClientConnect = 10000;
        /// <summary>
        /// 最大接收客户端联接数 默认值10000
        /// </summary>
        protected int MaxClientConnect
        {
            get { return _MaxClientConnect; }
        }


        /// <summary>
        /// SocketAsyncEventArgs 列队
        /// </summary>
        private Queue<SocketAsyncEventArgs> AysncQueue;


        /// <summary>
        /// 保存SOCKET 客户连接列表
        /// </summary>
        private System.Collections.Concurrent.BlockingCollection<Socket> clientlist;

        /// <summary>
        /// 返回客户SOCKET 列表
        /// </summary>
        public System.Collections.Concurrent.BlockingCollection<Socket> Clientlist
        {
            get
            {

                return clientlist;
            }

        }


        /// <summary>
        /// 为每个客户端联接所分配的缓冲区 大小默认50KB
        /// </summary>
        private int _MaxBuffCount = 1024 * 50;

        /// <summary>
        /// 为每个客户端联接所分配的缓冲区 大小默认50KB
        /// </summary>
        public int MaxBuffCount
        {
            get { return _MaxBuffCount; }
            set { _MaxBuffCount = value; }
        }

        #endregion


        #region 构造函数
        /// <summary>
        /// 创建一个新的异步Socket服务器对象
        /// </summary>
        /// <param name="endPoint">用于指定服务器的终节点</param>
        /// <param name="maxClientConnect"> 最大接收客户端联接数 默认值10000</param>
        public AsyncSocketServer(IPEndPoint endPoint, int maxClientConnect = 10000)
        {
            //初始化Socket 对像
            ServerListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //初始化Socket设置
            ServerListen.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            //初始化邦定端口对像变量
            _ServerEndPoint = endPoint;
            //初始化最大客户端联接数
            _MaxClientConnect = maxClientConnect;
        }
        #endregion

        #region SocketAsyncEventArgsPool Socket
        //System.Collections.Generic.IDictionary<string,SocketAsyncEventArgs> Socket
        #endregion
        public void CloseSocket(SocketAsyncEventArgs socket)
        {
            socket.Dispose();
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose( bool b)
        {
            if (b)
            {

                ServerListen.Close();
                ServerListen.Dispose();
                clientlist.Dispose();
            }
         }

        public event EventHandler<SocketAsyncEventArgs> OnAcceptSocket;

        public event EventHandler<SocketAsyncEventArgs> OnClientDisconnected;

        public event EventHandler<SocketAsyncEventArgs> OnReceiveData;

        public event EventHandler<SocketAsyncEventArgs> OnSendData;



        public void Start()
        {
            //可以帮定同一端口
            ServerListen.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            //端口重用
            ServerListen.ExclusiveAddressUse = false;
            //邦定端口开始监听
            ServerListen.Bind(ServerIPEndPoint);
            //可以有100外队列挂起
            ServerListen.Listen(100);

            //初始化联接 SocketAsyncEventArgs 队列 
            InitalizeQuery();

            StartSocketAccept();
        }
        /// <summary>
        ///开始接收新联接
        /// </summary>
        /// <param name="args"></param>
        protected void StartSocketAccept()
        {
            SocketAsyncEventArgs args = AysncQueue.Dequeue();
            args = args == null ? CreateSocketAsyncEventArgs() : args;
            args.Completed -= new EventHandler<SocketAsyncEventArgs>(SocketReceive_Completed);
            args.Completed += new EventHandler<SocketAsyncEventArgs>(SocketAccept_Completed);
            try
            {
                if (!ServerListen.AcceptAsync(args))
                {
                    SocketAccept_Completed(this, args);
                }
            }
            catch (SocketException)
            {
            }
            catch (ObjectDisposedException)
            {
            }
            catch (NotSupportedException)
            {
            }
            catch (ArgumentOutOfRangeException)
            {
            }
            catch (ArgumentException)
            {
            }
            catch (IndexOutOfRangeException)
            {
            }
        }

        void SocketAccept_Completed(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                Socket client = e.AcceptSocket;
                e.Completed -= new EventHandler<SocketAsyncEventArgs>(SocketAccept_Completed);
                e.Completed += new EventHandler<SocketAsyncEventArgs>(SocketReceive_Completed);


                if (e.SocketError == SocketError.Success)
                {
                    //联接引发事件
                    if (OnAcceptSocket != null)
                    {
                        OnAcceptSocket(this, e);
                    }

                    byte[] Bytes = new byte[MaxBuffCount];

                    //设置数据接收缓冲区
                    e.SetBuffer(Bytes, 0, MaxBuffCount);
                    //如果这个Socket对象不存在
                    Socket currentSocket = client;
                    //添加到Socket管理对像
                    if (!Clientlist.TryTake(out currentSocket))
                    {
                        Clientlist.TryAdd(client);
                    }
                    else
                    {
                        //如果已经存在则进行删除
                        client.Close();
                    }

                    //开始接收数据
                    if (!client.ReceiveAsync(e))
                    {
                        SocketReceive_Completed(client, e);
                    }
                }




            }
            catch (SocketException)
            {
                //引发OnClientDisconnected事件
                if (OnClientDisconnected != null)
                {
                    OnClientDisconnected(this, e);
                }
                //socket 断开后添加一个新的SocketAsyncEventArgs到队列中
                AysncQueue.Enqueue(e);

            }
            catch (ObjectDisposedException)
            {
                //引发OnClientDisconnected事件
                if (OnClientDisconnected != null)
                {
                    OnClientDisconnected(this, e);
                }
                //socket 断开后添加一个新的SocketAsyncEventArgs到队列中
                AysncQueue.Enqueue(e);
            }

            finally
            {
                StartSocketAccept();
            }

        }

        void SocketReceive_Completed(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                Socket socket = e.AcceptSocket;
                if (e.SocketError == SocketError.Success)
                {

                    if (e.BytesTransferred > 0)
                    {
                        byte[] receiveBuffer = new byte[e.BytesTransferred];
                        Array.Copy(e.Buffer, receiveBuffer, receiveBuffer.Length);

                        //引发Receive事件
                        if (OnReceiveData != null)
                        {
                            OnReceiveData(this, e);
                        }
                        //开始接收数据
                        if (!socket.ReceiveAsync(e))
                        {
                            SocketReceive_Completed(this, e);
                        }
                    }
                    else
                    {
                        Clientlist.TryTake(out socket);
                        if (socket != null)
                        {
                            socket.Shutdown(SocketShutdown.Both);
                            socket.Close();
                        }


                        //引发OnClientDisconnected事件
                        if (OnClientDisconnected != null)
                        {
                            OnClientDisconnected(this, e);
                        }

                        //socket 断开后添加一个新的SocketAsyncEventArgs到队列中
                        AysncQueue.Enqueue(e);
                    }
                }
                else
                {
                    Clientlist.TryTake(out socket);
                    if (socket != null)
                    {
                        socket.Shutdown(SocketShutdown.Both);
                        socket.Close();
                    }
                    //引发OnClientDisconnected事件
                    if (OnClientDisconnected != null)
                    {
                        OnClientDisconnected(this, e);
                    }
                    //socket 断开后添加一个新的SocketAsyncEventArgs到队列中
                    AysncQueue.Enqueue(e);
                }
            }
            catch (SocketException)
            {
                //引发OnClientDisconnected事件
                if (OnClientDisconnected != null)
                {
                    OnClientDisconnected(this, e);
                }
                //socket 断开后添加一个新的SocketAsyncEventArgs到队列中
                AysncQueue.Enqueue(e);

            }
            catch (ObjectDisposedException)
            {
                //引发OnClientDisconnected事件
                if (OnClientDisconnected != null)
                {
                    OnClientDisconnected(this, e);
                }
                //socket 断开后添加一个新的SocketAsyncEventArgs到队列中
                AysncQueue.Enqueue(e);
            }


        }





        public bool Stop()
        {
            try
            {
                Dispose();
            }
            catch (Exception)
            {

            }
            //断开所有联接
            Clientlist.ToArray().ToList().ForEach(o =>
            {
                if (o != null)
                {
                    try
                    {
                        o.Close();
                    }
                    catch (Exception)
                    {
                    }
                }
            });

            return true;
        }


        /// <summary>
        /// 初始化联接队列数据
        /// </summary>
        protected virtual void InitalizeQuery()
        {
            this.AysncQueue = new Queue<SocketAsyncEventArgs>(MaxClientConnect);
            this.clientlist = new System.Collections.Concurrent.BlockingCollection<Socket>(MaxBuffCount);
            //初始化队列
            for (int i = 0; i < MaxClientConnect; i++)
            {

                var e = CreateSocketAsyncEventArgs();
                AysncQueue.Enqueue(e);
            }
        }

        /// <summary>
        /// 创建一个 表示异步套接字操作
        /// </summary>
        /// <returns></returns>
        protected SocketAsyncEventArgs CreateSocketAsyncEventArgs()
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            //开始接收数据
            e.Completed += new EventHandler<SocketAsyncEventArgs>(SocketReceive_Completed);
            return e;
        }
    }
}
